package com.mingqijia.gassafety.job.job.warnStrategy;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Date;
import java.util.Calendar;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.mingqijia.gassafety.authority.api.resp.config.DictionaryItemRespDTO;
import com.mingqijia.gassafety.authority.dal.helper.ConfigureHolder;
import com.mingqijia.gassafety.db.entity.Consumer;
import com.mingqijia.gassafety.db.entity.Dtu;
import com.mingqijia.gassafety.db.entity.InformRecord;
import com.mingqijia.gassafety.db.entity.RunningReportAuditConfig;
import com.mingqijia.gassafety.db.entity.RunningReportConfig;
import com.mingqijia.gassafety.db.entity.RunningReport;
import com.mingqijia.gassafety.db.entity.RunningReportData;
import com.mingqijia.gassafety.db.entity.HistoryAlarm;
import com.mingqijia.gassafety.db.entity.HistoryBroken;
import com.mingqijia.gassafety.db.influxdb.config.InfluxDBConfiguration;
import com.mingqijia.gassafety.db.influxdb.config.InfluxDBConnect;
import com.mingqijia.gassafety.db.mapper.DtuMapper;
import com.mingqijia.gassafety.db.mapper.ConsumerMapper;
import com.mingqijia.gassafety.db.mapper.RunningReportAuditConfigMapper;
import com.mingqijia.gassafety.db.mapper.RunningReportConfigMapper;
import com.mingqijia.gassafety.db.mapper.RunningReportMapper;
import com.mingqijia.gassafety.db.mapper.RunningReportDataMapper;
import com.mingqijia.gassafety.db.mapper.HistoryAlarmMapper;
import com.mingqijia.gassafety.db.mapper.HistoryBrokenMapper;
import com.mingqijia.gassafety.job.feign.ConsoleSkFeignClient;
import com.mingqijia.gassafety.job.response.sk.ConsoleSkUserData;
import com.mingqijia.gassafety.job.response.sk.ConsoleSkUserListData;
import com.mingqijia.gassafety.job.response.sk.ConsoleSkUserListResponse;
import com.mingqijia.gassafety.job.service.RunningReportDataService;
import com.mingqijia.gassafety.shared.constant.AppealStateEnum;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.constant.OpenCloseEnum;
import com.mingqijia.gassafety.shared.constant.EquipmentType;
import com.mingqijia.gassafety.shared.constant.runningReport.ReportContentTypeEnum;
import com.mingqijia.gassafety.shared.dto.RunningReportOnOffDTO;
import com.mingqijia.gassafety.shared.dto.cms.CmsInfoResDTO;
import com.mingqijia.gassafety.shared.utils.ApplicationUtils;
import com.mingqijia.gassafety.shared.utils.RedisCacheExt;
import com.mingqijia.gassafety.shared.utils.commonUtils.DateUtils;
import com.mingqijia.gassafety.shared.utils.message.AppletMessageService;
import com.mingqijia.gassafety.shared.utils.message.CmsMessageService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.influxdb.dto.QueryResult;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author mby
 * @version 1.0.0
 * @ClassName RunningReportJob.java
 * @Description TODO
 * @createTime 2024年03月11日
 */
@Component
@Slf4j
public class RunningReportJob {

    @Value( "${gassafety.h5.common.path}" )
    private String h5CommonPath;

    @Autowired
    RedisCacheExt redisUtil;
    @Autowired
    DtuMapper dtuMapper;
    @Autowired
    ConsumerMapper consumerMapper;
    @Autowired
    RunningReportConfigMapper runningReportConfigMapper;
    @Autowired
    RunningReportMapper runningReportMapper;
    @Autowired
    RunningReportDataMapper runningReportDataMapper;
    @Autowired
    HistoryAlarmMapper historyAlarmMapper;
    @Autowired
    HistoryBrokenMapper historyBrokenMapper;
    @Autowired
    RunningReportAuditConfigMapper runningReportAuditConfigMapper;
    @Autowired
    RunningReportDataService runningReportDataService;
    @Autowired
    ConfigureHolder holder;
    @Autowired
    InfluxDBConfiguration influxDBConfiguration;

    @Autowired
    ConsoleSkFeignClient consoleSkFeignClient;
    @Autowired
    CmsMessageService cmsMessageService;

    @Autowired
    AppletMessageService appletMessageService;

    public static final Integer pageSize = 1000;

    /**  生成运行报告
     *   0 0 0 1/1 * ? 每天零点执行一次
     */
    @XxlJob("runningReportJob")
    public ReturnT<String> runningReportJob(String param) {
        XxlJobLogger.log("XXLJOB-runningReportJob start..." );
        log.info("runningReportJob--start--------");
        String key = Constants.EQUIPMENT_RUNNING_REPORT;
        try {
            Boolean acquire = redisUtil.setIfAbsent(key, String.valueOf(System.currentTimeMillis()), Constants.TIME_OUT_TWO_HOUR);//15分钟超时
            if (acquire) {
                try {
                    execute();
                    return ReturnT.SUCCESS;
                } catch (Exception e) {
                    log.info("runningReportJob-error:{}", e);
                } finally {
                    redisUtil.del(key);
                }
            }
        } catch (Exception e) {
            log.info("runningReportJob-error:{}", e);
        }
        log.info("runningReportJob--end--------");
        XxlJobLogger.log("XXLJOB-runningReportJob end..." );
        return ReturnT.SUCCESS;
    }

    private boolean execute() {
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        Date endDate = DateUtils.toDate(DateUtils.dateFormat(c.getTime(), "yyyy-MM"), "yyyy-MM"); //本月一开始的时间
        // 当月有多少天
        Integer monthDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        // 当月的第几天
        Integer today = c.get(Calendar.DAY_OF_MONTH);
        // 上个月
        c.add(Calendar.MONTH, -1);
        String reportDate = DateUtils.dateFormat(c.getTime(), "yyyy-MM");
        Integer lastMonthDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        Date startDate = DateUtils.toDate(reportDate, "yyyy-MM");  // 上个月一开始的时间
        Long startSecond = startDate.getTime() / 1000; // 上月开始毫秒数
        Long endSecond = endDate.getTime() / 1000; // 上月结束本月开始毫秒数
        log.info("runningReportJob-当月有{}天，当月第{}天，报告月份{},{},{},{}", monthDay, today, reportDate, lastMonthDay, startSecond, endSecond);

        // 如果当月只有28号，今天也是28号，可以查询生产日期设置为28，29，30，31的运行报告配置
        List<Integer> generateReportDayList = new ArrayList<>();
        generateReportDayList.add(today);
        if (today.equals(monthDay) && monthDay < 31)  {
            while (monthDay < 31) {
                monthDay ++;
                generateReportDayList.add(monthDay);
            }
        }
        log.info("runningReportJob-需要生成报告的日期配置{}", JSONObject.toJSONString(generateReportDayList));

        //当天需要生成的运行报告
        QueryWrapper<RunningReportConfig> configQueryWrapper = new QueryWrapper<>();
        configQueryWrapper.lambda().eq(RunningReportConfig::getIsDeleted,0)
            .eq(RunningReportConfig::getGenerateReportOpen, OpenCloseEnum.OPEN.getCode())
            .in(RunningReportConfig::getGenerateReportDay, generateReportDayList);
        List<RunningReportConfig> runningReportConfigs = runningReportConfigMapper.selectList(configQueryWrapper);
        if (CollectionUtils.isNotEmpty(runningReportConfigs)) {
            //会生成报告，有查开关机记录的需求，获取数据库连接
            InfluxDBConnect influxDBConnect = influxDBConfiguration.getInfluxDBConnect();
            for (RunningReportConfig config : runningReportConfigs) {
                log.info("runningReportJob-runningReportConfig:{}", config.toString());
                Integer offlineInterval = config.getOfflineInterval() == null ? null : config.getOfflineInterval() * 60 * 60; // 离线间隔设置，单位秒
                // 查看配置的审核信息
                Map<String, String> checkOpenMap = StringUtils.isNotEmpty(config.getCheckOpen()) ? JSON.parseObject(config.getCheckOpen(), Map.class) : new HashMap<>();
                Map<String, String> reasonMap = new HashMap<>();
                try {
                    List<DictionaryItemRespDTO> alarmReasonDict = holder.getDictionaryByKeyNoCache(
                            Constants.ALARM_REASON, config.getSpId());
                    reasonMap = alarmReasonDict.stream().collect(Collectors.toMap(DictionaryItemRespDTO::getValue, DictionaryItemRespDTO::getName));
                } catch(Exception e) {
                    log.info("runningReportJob-alarmReasonDict-error:{}", e.getMessage());
                }
                Map<String, String> alarmReasonMap = reasonMap;
                // 查询客户列表
                int pageIndex = 1;
                long total = 0;
                QueryWrapper<Consumer> consumerWrapper = new QueryWrapper<>();
                consumerWrapper.lambda().eq(Consumer::getIsDeleted, Constants.IS_DELETED_FALSE)
                    .eq(Consumer::getSpId, config.getSpId());
                do{
                    log.info("runningReportJob-pageIndex:{}", pageIndex);
                    Page<Consumer> pages = PageHelper.startPage(pageIndex, pageSize);
                    List<Consumer> consumers = consumerMapper.selectList(consumerWrapper);
                    pageIndex++;
                    total = pages.getTotal();
                    if (CollectionUtils.isNotEmpty(consumers)) {
                        consumers.stream().forEach(consumer -> {
                            // log.info("runningReportJob-consumer:{}", consumer.toString());
                            // 查询该客户上个月是否已经有了运行报告
                            QueryWrapper<RunningReport> reportQueryWrapper = new QueryWrapper<>();
                            reportQueryWrapper.lambda().eq(RunningReport::getIsDeleted,0)
                                .eq(RunningReport::getConsumerId,consumer.getId())
                                .eq(RunningReport::getReportDate,reportDate);
                            RunningReport oldRunningReport = runningReportMapper.selectOne(reportQueryWrapper);
                            if (oldRunningReport == null) {

                                RunningReport runningReport = new RunningReport();
                                runningReport.setConfigId(config.getId());
                                runningReport.setConsumerId(consumer.getId());
                                runningReport.setIndustryType(consumer.getIndustryType());
                                runningReport.setReportDate(reportDate);
                                List<String> equipmentType = dtuMapper.queryEquipmentTypeByConsumerId(consumer.getId());
                                // 查询设备类型相关信息
                                StringBuilder equipmentTypeString = new StringBuilder();
                                if (equipmentType.size() > 0) {
                                    // 没有设备的不生成运行报告
                                    for (String type : equipmentType) {
                                        if (!EquipmentType.POINT_TYPE_GAS_DETECTOR.getCode().equals(type)) {
                                            equipmentTypeString.append(type).append(Constants.STR_COMMA);
                                        }
                                    }
                                    runningReport.setDeviceType(equipmentTypeString.length() > 0 ? equipmentTypeString.deleteCharAt(equipmentTypeString.length() - 1).toString() : Constants.BLANK);

                                    runningReport.setAlarmPending(0);
                                    runningReport.setAlarmProcessing(0);
                                    runningReport.setAlarmProcessed(0);
                                    runningReport.setBrokenPending(0);
                                    runningReport.setBrokenProcessing(0);
                                    runningReport.setBrokenProcessed(0);
                                    runningReport.setOfflineTime(0L); // 离线时长
                                    runningReport.setOfflineTotal(0); // 离线记录总数
                                    runningReport.setReportContentType(Constants.BLANK);

                                    // 判断报警
                                    List<RunningReportData> reportDataList = new ArrayList<>();
                                    QueryWrapper<HistoryAlarm> historyAlarmQueryWrapper = new QueryWrapper<>();
                                    historyAlarmQueryWrapper.lambda().eq(HistoryAlarm::getConsumerId, consumer.getId())
                                            .eq(HistoryAlarm::getIsDeleted, 0)
                                            .ge(HistoryAlarm::getCreatedAt, startDate)
                                            .lt(HistoryAlarm::getCreatedAt, endDate);
                                    List<HistoryAlarm> historyAlarmList = historyAlarmMapper.selectList(historyAlarmQueryWrapper);
                                    if (historyAlarmList.size() > 0) {
                                        runningReport.setReportContentType(runningReport.getReportContentType() + ReportContentTypeEnum.ALARM.getCode() + Constants.STR_COMMA); //有报警
                                        historyAlarmList.stream().forEach(alarm -> {
                                            RunningReportData data = new RunningReportData();
                                            data.setImei(alarm.getIMEI());
                                            data.setAlarmAddress(dtuMapper.queryAddressByImei(alarm.getIMEI()));
                                            data.setAlarmTime(alarm.getCreatedAt());
                                            data.setAlarmType(0);
                                            data.setConcentration(alarm.getConcentration());
                                            //安装调试，工单调试
                                            if (AppealStateEnum.HANDLED_INSTALL.getCode().equals(alarm.getAppealStatus()) ||
                                                    AppealStateEnum.HANDLED_TEST.getCode().equals(alarm.getAppealStatus())) {
                                                data.setValveBrokenInfo("设备调试");
                                            } else if (AppealStateEnum.HANDLING.getCode().equals(alarm.getAppealStatus()) ||
                                                    AppealStateEnum.FINISHED.getCode().equals(alarm.getAppealStatus())) {//转工单处理
                                                data.setValveBrokenInfo("转线下处理");
                                            } else {
                                                data.setValveBrokenInfo(StringUtils.isNotEmpty(alarm.getValveBrokenInfo()) ? alarmReasonMap.getOrDefault(alarm.getValveBrokenInfo(), Constants.BLANK) : Constants.BLANK);
                                            }
                                            data.setAppealTime(alarm.getAppealTime());
                                            if (alarm.getAppealStatus() == 0) {
                                                // 报警未处理
                                                data.setAppealStatus(0);
                                                runningReport.setAlarmPending(runningReport.getAlarmPending() + 1);
                                            } else if (alarm.getAppealStatus() == 1 || alarm.getAppealStatus() == 4) {
                                                // 报警处理中
                                                data.setAppealStatus(1);
                                                runningReport.setAlarmProcessing(runningReport.getAlarmProcessing() + 1);
                                            } else {
                                                // 报警已处理
                                                data.setAppealStatus(2);
                                                runningReport.setAlarmProcessed(runningReport.getAlarmProcessed() + 1);
                                            }
                                            data.setSpId(consumer.getSpId());
                                            reportDataList.add(data);
                                        });
                                    }

                                    // 判断故障
                                    QueryWrapper<HistoryBroken> historyBrokenQueryWrapper = new QueryWrapper<>();
                                    historyBrokenQueryWrapper.lambda().eq(HistoryBroken::getConsumerId, consumer.getId())
                                            .eq(HistoryBroken::getIsDeleted, 0)
                                            .ge(HistoryBroken::getCreatedAt, startDate)
                                            .lt(HistoryBroken::getCreatedAt, endDate);
                                    List<HistoryBroken> historyBrokenList = historyBrokenMapper.selectList(historyBrokenQueryWrapper);
                                    if (historyBrokenList.size() > 0) {
                                        runningReport.setReportContentType(runningReport.getReportContentType() + ReportContentTypeEnum.BROKEN.getCode() + Constants.STR_COMMA); //有故障
                                        historyBrokenList.stream().forEach(broken -> {
                                            RunningReportData data = new RunningReportData();
                                            data.setImei(broken.getIMEI());
                                            data.setAlarmAddress(dtuMapper.queryAddressByImei(broken.getIMEI()));
                                            data.setAlarmTime(broken.getCreatedAt());
                                            data.setAlarmType(1);
                                            String reasonStr = broken.getReason();
                                            if (StringUtils.isNotEmpty(broken.getReason()) && StringUtils.isNotEmpty(broken.getValveBrokenInfo())) {
                                                reasonStr = broken.getReason() + ";" + broken.getValveBrokenInfo();
                                            } else if (StringUtils.isEmpty(broken.getReason()) && StringUtils.isNotEmpty(broken.getValveBrokenInfo())) {
                                                reasonStr = broken.getValveBrokenInfo();
                                            }
                                            if (StringUtils.isNotEmpty(reasonStr)) {
                                                reasonStr = reasonStr.replaceAll("^;+|;+$", "");
                                            }
                                            data.setValveBrokenInfo(StringUtils.isEmpty(reasonStr) ? Constants.BLANK : reasonStr.replace(";正常", Constants.BLANK).replace("正常", Constants.BLANK));
                                            data.setAppealTime(broken.getAppealTime());
                                            if (broken.getAppealStatus() == 0) {
                                                // 报警未处理
                                                data.setAppealStatus(0);
                                                runningReport.setBrokenPending(runningReport.getBrokenPending() + 1);
                                            } else if (broken.getAppealStatus() == 1 || broken.getAppealStatus() == 4) {
                                                // 报警处理中
                                                data.setAppealStatus(1);
                                                runningReport.setBrokenProcessing(runningReport.getBrokenProcessing() + 1);
                                            } else {
                                                // 报警已处理
                                                data.setAppealStatus(2);
                                                runningReport.setBrokenProcessed(runningReport.getBrokenProcessed() + 1);
                                            }
                                            data.setSpId(consumer.getSpId());
                                            reportDataList.add(data);
                                        });
                                    }

                                    // 判断离线  设备长时间未通讯，设备拔电，设备未上电激活
                                    // 需要 1.先打开离线统计的配置  2.设备不属于点型可燃气体探测器类型
                                    if (config.getIsOfflineConfig() != null && config.getIsOfflineConfig() == 0) {
                                        // 查询该客户下所有的设备，不包含点型可燃气体探测器类型的
                                        LambdaQueryWrapper<Dtu> queryWrapper = new LambdaQueryWrapper();
                                        queryWrapper.eq(Dtu::getConsumerId, consumer.getId())
                                                .ne(Dtu::getEquipmentType, EquipmentType.POINT_TYPE_GAS_DETECTOR.getCode())
                                                .eq(Dtu::getIsDeleted, Constants.IS_DELETED_FALSE)
                                                .eq(Dtu::getSpId, consumer.getSpId());
                                        List<Dtu> dtuList = dtuMapper.selectList(queryWrapper);
                                        if (CollectionUtils.isNotEmpty(dtuList)) {
                                            for (Dtu dtu : dtuList) {
                                                // 查询离线情况
                                                // 查询本月开关机记录

                                                List<RunningReportOnOffDTO> thisMonthOnOffDataList = getOnOffDataList(influxDBConnect, dtu, DateUtils.format(startDate, "yyyy-MM-dd HH:mm:ss"), DateUtils.format(endDate, "yyyy-MM-dd HH:mm:ss"));
                                                if (CollectionUtils.isEmpty(thisMonthOnOffDataList)) {
                                                    // 查询上一条
                                                    RunningReportOnOffDTO lastMonthOnOffData = getLastOnOffData(influxDBConnect, dtu, DateUtils.format(startDate, "yyyy-MM-dd HH:mm:ss"));
                                                    if (lastMonthOnOffData == null) {
                                                        // 上一条是空，设备未上电激活
                                                        RunningReportData data = new RunningReportData();
                                                        data.setImei(dtu.getIMEI());
                                                        data.setAlarmAddress(dtu.getInstallationPosition());
                                                        data.setAlarmType(2); // 离线
                                                        data.setValveBrokenInfo("设备未上电激活");
                                                        // 浓度值字段用来保存离线时间秒数
                                                        data.setOfflineTime(Long.valueOf(lastMonthDay * 24 * 60 * 60));
                                                        runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                                        runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                                        data.setSpId(consumer.getSpId());
                                                        reportDataList.add(data);
                                                    }
                                                    if (lastMonthOnOffData != null && lastMonthOnOffData.isOffline()) {
                                                        // 上一条是离线
                                                        // 正常离线 / 周期性离线 + 离线配置开启，周期性离线计入统计
                                                        if (lastMonthOnOffData.getOfflineType() == 0 ||
                                                                (lastMonthOnOffData.getOfflineType() == 1 && config.getOfflineInclude() == 1)) {
                                                            // 正常离线,离线时间为当月时长
                                                            RunningReportData data = new RunningReportData();
                                                            data.setImei(dtu.getIMEI());
                                                            data.setAlarmAddress(dtu.getInstallationPosition());
                                                            data.setAlarmTime(lastMonthOnOffData.getTime());
                                                            data.setAlarmType(2); // 离线
                                                            data.setValveBrokenInfo(lastMonthOnOffData.getOfflineType() == 0 ? "设备拔电" : "设备长时间未通讯");
                                                            data.setOfflineTime(Long.valueOf(lastMonthDay * 24 * 60 * 60));
                                                            data.setOfflineExtend(1); // 跨月
                                                            data.setAlarmTime(lastMonthOnOffData.getTime());
                                                            runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                                            runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                                            data.setSpId(consumer.getSpId());
                                                            reportDataList.add(data);
                                                        }
                                                    }
                                                    // 上一条是在线，本月没有，那就不会有离线时间,不会计入明细
//                                                if (lastMonthOnOffData != null && !lastMonthOnOffData.isOffline()) {
//                                                    // 上一条是在线，本月没有，那就不会有离线时间
//                                                }

                                                } else {
                                                    // 本月数据不为空
                                                    // 判断也没有之前的数据，来判断是不是首次上电激活
                                                    boolean activation = false;
                                                    RunningReportOnOffDTO lastMonthOnOffData = getLastOnOffData(influxDBConnect, dtu, DateUtils.format(startDate, "yyyy-MM-dd HH:mm:ss"));
                                                    RunningReportOnOffDTO nextMonthOnOffData = getNextOnOffData(influxDBConnect, dtu, DateUtils.format(endDate, "yyyy-MM-dd HH:mm:ss"));
                                                    if (lastMonthOnOffData == null) {
                                                        activation = true;
                                                    }
                                                    // 把上一个月的最后一条数据和下一个月的第一条数据组装进来
                                                    boolean lastOffline = false;
                                                    Integer lastOfflineType = 0;
                                                    Date lastTime = null;
                                                    Long lastSecond = 0L;
                                                    assembleOnOffDataList(thisMonthOnOffDataList, lastMonthOnOffData, nextMonthOnOffData);
                                                    for (int i = 0; i < thisMonthOnOffDataList.size(); i++) {
                                                        if (i == 0) {
                                                            // 第一条
                                                            lastOffline = thisMonthOnOffDataList.get(i).isOffline();
                                                            lastOfflineType = thisMonthOnOffDataList.get(i).getOfflineType();
                                                            lastTime = thisMonthOnOffDataList.get(i).getTime();
                                                            lastSecond = thisMonthOnOffDataList.get(i).getSecond();
                                                            // 如果有未激活标记，首次需要登记设备未上电激活离线数据
                                                            if (activation) {
                                                                RunningReportData data = new RunningReportData();
                                                                data.setImei(dtu.getIMEI());
                                                                data.setAlarmAddress(dtu.getInstallationPosition());
                                                                data.setAlarmType(2); // 离线
                                                                data.setValveBrokenInfo("设备未上电激活");
                                                                data.setOfflineTime((endSecond > thisMonthOnOffDataList.get(i).getSecond() ? thisMonthOnOffDataList.get(i).getSecond() : endSecond) - startSecond);
                                                                runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                                                runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                                                data.setSpId(consumer.getSpId());
                                                                reportDataList.add(data);
                                                            }
                                                        } else {
                                                            // 不是第一条
                                                            if (thisMonthOnOffDataList.get(i).isOffline()) {
                                                                // 关机
                                                                // 如果上一条是开机  不需要计入离线，但需要更新
                                                                // 如果上一条是关机  真实关机  周期性关机 不计入离线
                                                                // 真实关机-真实关机  不更新
                                                                // 真实关机-周期性关机 不更新
                                                                // 周期性关机 -真实关机 更新
                                                                // 周期性关机-周期性关机  不更新
                                                                if ((lastOffline && lastOfflineType == 1 && thisMonthOnOffDataList.get(i).getOfflineType() == 0)
                                                                        || !lastOffline) {
                                                                    lastOffline = thisMonthOnOffDataList.get(i).isOffline();
                                                                    lastOfflineType = thisMonthOnOffDataList.get(i).getOfflineType();
                                                                    lastTime = thisMonthOnOffDataList.get(i).getTime();
                                                                    lastSecond = thisMonthOnOffDataList.get(i).getSecond();
                                                                }
                                                            } else {
                                                                // 开机
                                                                // 如果上一条是开机 不需要计入离线，也不需要更新
                                                                // 如果上一条是关机
                                                                if (lastOffline) {
                                                                    // 上一条是关机
                                                                    if (lastOfflineType == 0) {
                                                                        // 上报离线 没有设置计算时间间隔，或者离线间隔大于设置的
                                                                        if (offlineInterval == null || thisMonthOnOffDataList.get(i).getSecond() - lastSecond > offlineInterval) {
                                                                            RunningReportData data = new RunningReportData();
                                                                            data.setImei(dtu.getIMEI());
                                                                            data.setAlarmAddress(dtu.getInstallationPosition());
                                                                            data.setAlarmTime(lastTime);
                                                                            data.setAlarmType(2); // 离线
                                                                            data.setValveBrokenInfo("设备拔电");
                                                                            data.setOfflineTime((endSecond > thisMonthOnOffDataList.get(i).getSecond() ? thisMonthOnOffDataList.get(i).getSecond() : endSecond) -
                                                                                    (startSecond > lastSecond ? startSecond : lastSecond));
                                                                            if (startSecond > lastSecond) {
                                                                                data.setOfflineExtend(1); // 跨月
                                                                            }
                                                                            runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                                                            runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                                                            data.setSpId(consumer.getSpId());
                                                                            reportDataList.add(data);
                                                                            lastOffline = thisMonthOnOffDataList.get(i).isOffline();
                                                                            lastOfflineType = thisMonthOnOffDataList.get(i).getOfflineType();
                                                                            lastTime = thisMonthOnOffDataList.get(i).getTime();
                                                                            lastSecond = thisMonthOnOffDataList.get(i).getSecond();
                                                                        }
                                                                    } else if (lastOfflineType == 1) {
                                                                        // 周期性离线,判断
                                                                        if (config.getOfflineInclude() == 1) {
                                                                            RunningReportData data = new RunningReportData();
                                                                            data.setImei(dtu.getIMEI());
                                                                            data.setAlarmAddress(dtu.getInstallationPosition());
                                                                            data.setAlarmTime(lastTime);
                                                                            data.setAlarmType(2); // 离线
                                                                            data.setValveBrokenInfo("设备长时间未通讯");
                                                                            data.setOfflineTime((endSecond > thisMonthOnOffDataList.get(i).getSecond() ? thisMonthOnOffDataList.get(i).getSecond() : endSecond) -
                                                                                    (startSecond > lastSecond ? startSecond : lastSecond));
                                                                            if (startSecond > lastSecond) {
                                                                                data.setOfflineExtend(1); // 跨月
                                                                            }
                                                                            runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                                                            runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                                                            data.setSpId(consumer.getSpId());
                                                                            reportDataList.add(data);
                                                                            lastOffline = thisMonthOnOffDataList.get(i).isOffline();
                                                                            lastOfflineType = thisMonthOnOffDataList.get(i).getOfflineType();
                                                                            lastTime = thisMonthOnOffDataList.get(i).getTime();
                                                                            lastSecond = thisMonthOnOffDataList.get(i).getSecond();
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        // 如果是最后一条，并且最后一条在本月，并且是关机
                                                        if (i > 0 && i == thisMonthOnOffDataList.size() -1 && nextMonthOnOffData == null
                                                                && thisMonthOnOffDataList.get(i).isOffline()) {
                                                            if (thisMonthOnOffDataList.get(i).getOfflineType() == 0) {
                                                                // 必定超过记录时间，必定记录
                                                                RunningReportData data = new RunningReportData();
                                                                data.setImei(dtu.getIMEI());
                                                                data.setAlarmAddress(dtu.getInstallationPosition());
                                                                data.setAlarmTime(thisMonthOnOffDataList.get(i).getTime());
                                                                data.setAlarmType(2); // 离线
                                                                data.setValveBrokenInfo("设备拔电");
                                                                data.setOfflineTime(endSecond - thisMonthOnOffDataList.get(i).getSecond());
                                                                runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                                                runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                                                data.setSpId(consumer.getSpId());
                                                                reportDataList.add(data);
                                                            } else if (thisMonthOnOffDataList.get(i).getOfflineType() == 1) {
                                                                // 周期性离线
                                                                if (config.getOfflineInclude() == 1) {
                                                                    RunningReportData data = new RunningReportData();
                                                                    data.setImei(dtu.getIMEI());
                                                                    data.setAlarmAddress(dtu.getInstallationPosition());
                                                                    data.setAlarmTime(thisMonthOnOffDataList.get(i).getTime());
                                                                    data.setAlarmType(2); // 离线
                                                                    data.setValveBrokenInfo("设备长时间未通讯");
                                                                    data.setOfflineTime(endSecond - thisMonthOnOffDataList.get(i).getSecond());
                                                                    runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                                                    runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                                                    data.setSpId(consumer.getSpId());
                                                                    reportDataList.add(data);
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    if (StringUtils.isEmpty(consumer.getCustType())) {
                                        consumer.setCustType(StringUtils.isEmpty(consumer.getSubsCode()) ? "其他" : "未知");
                                    }

                                    // 报告内容
                                    if (runningReport.getOfflineTotal() > 0) {
                                        runningReport.setReportContentType(runningReport.getReportContentType() + ReportContentTypeEnum.OFFLINE.getCode() + Constants.STR_COMMA); //有报警
                                    }
                                    if (StringUtils.isBlank(runningReport.getReportContentType())) {
                                        runningReport.setReportContentType(ReportContentTypeEnum.NO_ALARM.getCode().toString());
                                    } else {
                                        runningReport.setReportContentType(runningReport.getReportContentType().substring(0, runningReport.getReportContentType().length() - 1));
                                    }
                                    // 查看审核设置，未审核-无需审核
                                    // 查询无需审核配置列表
                                    QueryWrapper<RunningReportAuditConfig> runningReportAuditConfigWrapper = new QueryWrapper<>();
                                    runningReportAuditConfigWrapper.lambda().eq(RunningReportAuditConfig::getConfigId, config.getId())
                                            .eq(RunningReportAuditConfig::getIsDeleted, Constants.IS_DELETED_FALSE)
                                            .eq(RunningReportAuditConfig::getSpId, config.getSpId());
                                    List<RunningReportAuditConfig> auditConfigList = runningReportAuditConfigMapper.selectList(runningReportAuditConfigWrapper);
                                    Map<String, List<Integer>> noAuditConfigMap = getNoAuditConfigMap(auditConfigList);
                                    if (noAuditConfigMap.get(consumer.getCustType()) != null) {
                                        // 匹配报警记录状态
                                        String[] contentTypeArr = runningReport.getReportContentType().split(Constants.STR_COMMA);
                                        for (String contentType : contentTypeArr) {
                                            if (noAuditConfigMap.get(consumer.getCustType()).contains(Integer.parseInt(contentType))) {
                                                // 满足无需审核配置
                                                runningReport.setCheckStatus(2);
                                                break;
                                            }
                                        }
                                    }
                                    if (runningReport.getCheckStatus() != null && runningReport.getCheckStatus() == 2) {
                                        // 无需审核相当于审核通过，需要发站内信

                                    } else {
                                        // 没有无需审核配置，未审核
                                        runningReport.setCheckStatus(0);
                                    }

                                    runningReport.setUpdateStatus(0);
                                    runningReport.setIsDeleted(false);
                                    runningReport.setCreatedAt(new Date());
                                    runningReport.setSpId(consumer.getSpId());
                                    runningReportMapper.insert(runningReport);
                                    for (RunningReportData data : reportDataList) {
                                        data.setReportId(runningReport.getId());
                                    }
                                    runningReportDataService.saveBatch(reportDataList);
                                }
                            }
                        });
                    }
                }while(total > (pageIndex - 1) * pageSize);
            }

        }

        return true;
    }

    /**
     * 根据无需审核配置获取所有无需审核的组合
     * @param auditConfigList
     * @return
     */
    public Map<String, List<Integer>> getNoAuditConfigMap(List<RunningReportAuditConfig> auditConfigList) {

        Map<String, List<Integer>> noAuditConfigMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(auditConfigList)) {
            for (RunningReportAuditConfig runningReportAuditConfig : auditConfigList) {
                List<String> custTypeList = getCustTypeList(runningReportAuditConfig.getCustType(), runningReportAuditConfig.getSpId());
                List<Integer> alarmStatusList = getAlarmStatus(runningReportAuditConfig.getAlarmStatus());
                for (String custType : custTypeList) {
                    for (Integer alarmStatus : alarmStatusList) {
                        if (noAuditConfigMap.get(custType) == null) {
                            noAuditConfigMap.put(custType, new ArrayList<>());
                        }
                        noAuditConfigMap.get(custType).add(alarmStatus);

                    }
                }

            }
        }
        return noAuditConfigMap;
    }

    /**
     * 根据spId获取用户类型列表
     * @param custType
     * @return
     */
    public List<String> getCustTypeList(String custType, String spId) {
        if (StringUtils.isNotBlank(custType)) {
            return Arrays.asList(custType);
        }

        List<String> custTypes = consumerMapper.selectUserType(spId);
        if (CollectionUtils.isNotEmpty(custTypes)) {
            custTypes.remove("");
            // 其他
            if (consumerMapper.selectUserTypeCount(spId, "其他") > 0) {
                custTypes.add("其他");
            }
            // 未知
            if (consumerMapper.selectUserTypeCount(spId, "未知") > 0) {
                custTypes.add("未知");
            }
        }

        return custTypes;
    }

    /**
     * 根据spId获取用户类型列表
     * @return
     */
    public List<Integer> getAlarmStatus(Integer alarmStatus) {
        List<Integer> alarmStatusList = new ArrayList<>();
        if (alarmStatus == 0) {
            alarmStatusList.addAll(Arrays.asList(1,2,3,4));
        } else {
            alarmStatusList.add(alarmStatus);
        }

        return alarmStatusList;
    }

    /**
     * 根据无需审核配置获取所有无需审核的组合
     * @param
     * @return
     */
    public List<RunningReportOnOffDTO> getOnOffDataList(InfluxDBConnect influxDBConnect, Dtu dtu, String startTime, String nextTime) {
        List<RunningReportOnOffDTO> resultList = new ArrayList<>();
        // 查询本月开关机记录
        String selectSql = new StringBuffer("select * from PowerLogAsDtu where Path='").append(dtu.getPath())
            .append("' AND DtuId = '").append(dtu.getIMEI()).append("' AND ConsumerId = ").append(dtu.getConsumerId())
            .append(" AND time > '").append(startTime).append("' AND time < '").append(nextTime)
            .append("' order by time asc").toString();
        log.info("runningReportJob-getOnOffDataList-selectSql:{}", selectSql);
        QueryResult thisMonthResult = influxDBConnect.query(selectSql);
        List<List<Object>> list = new ArrayList<>();
        List<String> columns = new ArrayList<>();
        if (thisMonthResult.getResults().get(0).getSeries() != null) {
            columns = thisMonthResult.getResults().get(0).getSeries().get(0).getColumns();
            list = thisMonthResult.getResults().get(0).getSeries().get(0).getValues();
        }
        log.info("runningReportJob-getOnOffDataList:{}", list.toString());
        for (List<Object> objects : list) {
            //log.info("objects1：{}", objects.get(9));
            RunningReportOnOffDTO res = new RunningReportOnOffDTO();
            res.setOffline(Boolean.valueOf(objects.get(columns.indexOf("Offline")).toString()));
            res.setOfflineType(0);
            if (res.isOffline() && objects.get(columns.indexOf("Version")).toString().equals("1000")) {
                res.setOfflineType(1); // 周期性离线
            }
            res.setTime(DateUtil.parse(objects.get(columns.indexOf("time")).toString()));
            res.setSecond(res.getTime().getTime() / 1000);

            resultList.add(res);
        }
        return resultList;
    }

    /**
     * 根据无需审核配置获取所有无需审核的组合
     * @param
     * @return
     */
    public RunningReportOnOffDTO getLastOnOffData(InfluxDBConnect influxDBConnect, Dtu dtu, String startTime) {
        // 查询本月的上一条开关机记录
        String selectSql = new StringBuffer("select * from PowerLogAsDtu where Path='").append(dtu.getPath())
            .append("' AND DtuId = '").append(dtu.getIMEI()).append("' AND ConsumerId = ").append(dtu.getConsumerId())
                .append(" AND time < '").append(startTime)
                .append("' order by time desc limit 1 offset 0").toString();
        QueryResult thisMonthResult = influxDBConnect.query(selectSql);
        List<List<Object>> list = new ArrayList<>();
        List<String> columns = new ArrayList<>();
        if (thisMonthResult.getResults().get(0).getSeries() != null) {
            columns = thisMonthResult.getResults().get(0).getSeries().get(0).getColumns();
            list = thisMonthResult.getResults().get(0).getSeries().get(0).getValues();
        }
        log.info("runningReportJob-getLastOnOffData:{}", list.toString());
        for (List<Object> objects : list) {
            RunningReportOnOffDTO res = new RunningReportOnOffDTO();
            res.setOffline(Boolean.valueOf(objects.get(columns.indexOf("Offline")).toString()));
            res.setOfflineType(0);
            if (res.isOffline() && objects.get(columns.indexOf("Version")).toString().equals("1000")) {
                res.setOfflineType(1); // 周期性离线
            }
            res.setTime(DateUtil.parse(objects.get(columns.indexOf("time")).toString()));
            res.setSecond(res.getTime().getTime() / 1000);

            return res;
        }
        return null;
    }

    /**
     * 根据无需审核配置获取所有无需审核的组合
     * @param
     * @return
     */
    public RunningReportOnOffDTO getNextOnOffData(InfluxDBConnect influxDBConnect, Dtu dtu, String nextTime) {
        // 查询本月的下一条开关机记录
        String selectSql = new StringBuffer("select * from PowerLogAsDtu where Path='").append(dtu.getPath())
            .append("' AND DtuId = '").append(dtu.getIMEI()).append("' AND ConsumerId = ").append(dtu.getConsumerId())
            .append(" AND time > '").append(nextTime)
            .append("' order by time asc limit 1 offset 0").toString();
        QueryResult thisMonthResult = influxDBConnect.query(selectSql);
        List<List<Object>> list = new ArrayList<>();
        List<String> columns = new ArrayList<>();
        if (thisMonthResult.getResults().get(0).getSeries() != null) {
            columns = thisMonthResult.getResults().get(0).getSeries().get(0).getColumns();
            list = thisMonthResult.getResults().get(0).getSeries().get(0).getValues();
        }
        log.info("runningReportJob-getNextOnOffData:{}", list.toString());
        for (List<Object> objects : list) {
            RunningReportOnOffDTO res = new RunningReportOnOffDTO();
            res.setOffline(Boolean.valueOf(objects.get(columns.indexOf("Offline")).toString()));
            res.setOfflineType(0);
            if (res.isOffline() && objects.get(columns.indexOf("Version")).toString().equals("1000")) {
                res.setOfflineType(1); // 周期性离线
            }
            res.setTime(DateUtil.parse(objects.get(columns.indexOf("time")).toString()));
            res.setSecond(res.getTime().getTime() / 1000);

            return res;
        }
        return null;
    }

    /**
     * 组装列表
     * @param list 列表数据
     * @param lastData 上一条数据
     * @param nextData 下一条数据
     * @return
     */
    public void assembleOnOffDataList(List<RunningReportOnOffDTO> list, RunningReportOnOffDTO lastData, RunningReportOnOffDTO nextData) {
        if (lastData != null) {
            list.add(0, lastData);
        }
        if (nextData != null) {
            list.add(nextData);
        }
    }

    public void pushMsg(RunningReport runningReport) {
        QueryWrapper<Dtu> query = new QueryWrapper<>();
        query.lambda().or().eq(Dtu::getIsDeleted, 0)
                .eq(Dtu::getSpId, runningReport.getSpId())
                .eq(Dtu::getConsumerId, runningReport.getConsumerId());
        List<Dtu> dtus = dtuMapper.selectList(query);
        List<ConsoleSkUserListData> consoleSkUserListData = new ArrayList<>();
        List<Integer> userId = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dtus)) {
            for (Dtu dtu : dtus) {
                if (!dtu.getIMEI().contains("-")) {
                    log.info("运行报告查询家庭成员" + dtu.getIMEI());
                    ConsoleSkUserListResponse consoleSkUserListResponse = consoleSkFeignClient
                            .alarmSOSUserList(dtu.getIMEI());
                    log.info(new StringBuilder().append("需要给运行报告").append(dtu.getIMEI()).append("的家庭成员发送信息，信息如下")
                            .append(consoleSkUserListResponse).toString());
                    //String title = Constants.RUNNING_REPORT_MESSAGE_TITLE;
                    if (consoleSkUserListResponse != null && consoleSkUserListResponse.getData() != null
                            && CollectionUtil.isNotEmpty(consoleSkUserListResponse.getData().getUserList())) {
                        if (!userId.contains(consoleSkUserListResponse.getData().getHomeId())) {
                            userId.add(consoleSkUserListResponse.getData().getHomeId());
                            consoleSkUserListData.add(consoleSkUserListResponse.getData());
                        }
                    }
                }
            }
        }
        log.info("运行报告开始发送消息的具体内容为" + consoleSkUserListData);
        String title = Constants.RUNNING_REPORT_MESSAGE_TITLE;
        String wapUrl = String.format(Constants.RUNNINGREPORT_PREVIEW, Constants.BLANK, runningReport.getReportDate(), Constants.BLANK, Constants.BLANK);
        String appUrl = String.format(Constants.RUNNINGREPORT_H5, h5CommonPath, Constants.BLANK, runningReport.getReportDate(), Constants.BLANK, Constants.BLANK);
        if (CollectionUtils.isNotEmpty(consoleSkUserListData)) {
            for (ConsoleSkUserListData consoleSkUserListDatum : consoleSkUserListData) {
                String msgs = String.format(Constants.RUNNING_REPORT_SEND_MESSAGE, consoleSkUserListDatum.getHomeName(), runningReport.getReportDate());;

                // 循环发送家庭其他成员
                for (ConsoleSkUserData consoleSkUserData : consoleSkUserListDatum.getUserList()) {
                    // 站内信参数封装
                    cn.hutool.json.JSONObject cmsReqParams = cmsMessageService.getCmsJSONParams(msgs, title,
                            consoleSkUserData.getUserId(), wapUrl, appUrl);
                    // 站内信发送

                    CmsInfoResDTO cmsInfoResDTO = cmsMessageService.sendCmsMsg(cmsReqParams);
                    log.info("运行报告APP站内信发送-request：{}，response：{}" ,cmsReqParams, cmsInfoResDTO);
                    // 小程序参数封装
                    cn.hutool.json.JSONObject appletJSONParams = appletMessageService.getRunningReportParams(consoleSkUserListDatum.getHomeName(),
                            consoleSkUserData.getUserId(), title, runningReport.getReportDate(), wapUrl);
                    // 小程序发送
                    CmsInfoResDTO cmsInfoResDTO2 = appletMessageService.sendAppletMsg(appletJSONParams);
                    log.info("运行报告小程序站内信发送-request：{}，response：{}" ,appletJSONParams, cmsInfoResDTO2);
                }
            }
        }

    }
}